package com.bes.main;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.fastjson.JSON;
import com.bes.main.bean.CVE;
import com.bes.main.bean.Metrics;
import com.bes.main.excel.CVEExcel;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.helper.StringUtil;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import javax.swing.text.html.HTML;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class Main {

    private static final List<String> urls = Arrays.asList("https://tomcat.apache.org/security-11.html", "https://tomcat.apache.org/security-10.html", "https://tomcat.apache.org/security-9.html", "https://tomcat.apache.org/security-8.html");

    private static String time;

    public static void main(String[] args) {
        if (args != null && args.length > 0) {
            time = args[0];
        }


        List<CVE> cveList = new ArrayList<>();
        try {
            Map<String, List<String>> allCVE = new HashMap<>();
            getAllCVE(allCVE);

            for (String cveString : allCVE.keySet()) {
                String response = getResponse("https://cveawg.mitre.org/api/cve/" + cveString);

                CVE cve = JSON.parseObject(response, CVE.class);
                cve.setVersions(allCVE.get(cveString));
                cveList.add(cve);
            }
            exportExcel(cveList);
        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
    }

    private static void exportExcel(List<CVE> cveList) {
        String fileName = "tomcat_cve.xlsx";

        try (ExcelWriter excelWriter = EasyExcel.write(fileName, CVEExcel.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build()) {
            // 去调用写入,这里我调用了五次，实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面

            Map<String, List<CVEExcel>> versionCve = new HashMap<>();
            List<CVEExcel> allCVEExcel = new ArrayList<>();

            WriteSheet writeSheet = EasyExcel.writerSheet(0, "cve").build();
            for (CVE cve : cveList) {
                CVEExcel excel = new CVEExcel();
                excel.setCveId(cve.getCveMetadata().getCveId());
                excel.setDatePublished(cve.getCveMetadata().getDatePublished());

                List<Metrics> metrics = cve.getContainers().getCna().getMetrics();
                if (metrics != null && !metrics.isEmpty()) {
                    excel.setMetrics(metrics.get(0).getOther().getContent().getText());
                }

                List<String> cveVersions = cve.getVersions();
                for (String cveVersion : cveVersions) {
                    List<CVEExcel> cveExcels = versionCve.computeIfAbsent(cveVersion, k -> new ArrayList<>());
                    cveExcels.add(excel);
                }
                excel.setVersion(StringUtil.join(cveVersions, ","));
                allCVEExcel.add(excel);
            }

            excelWriter.write(allCVEExcel, writeSheet);

            int index = 1;
            for (String version : versionCve.keySet()) {
                WriteSheet writeSheetVersion = EasyExcel.writerSheet(index++, version).build();
                excelWriter.write(versionCve.get(version), writeSheetVersion);
            }

        }
    }

    private static void getAllCVE(Map<String, List<String>> res) throws IOException, ParseException {
        for (String url : urls) {
            String htmlString = getResponse(url);
            getCVEList(htmlString, res);
        }
    }

    private static void getCVEList(String htmlString, Map<String, List<String>> res) throws ParseException {
        Document document = Jsoup.parse(htmlString);

        Element element = document.child(0);

        Element content = element.getElementsByAttributeValue("id", "content").get(0);

        Elements elements = content.children();
        Iterator<Element> iterator = elements.iterator();
        while (iterator.hasNext()) {
            Element childElement = iterator.next();
            if (!HTML.Tag.H3.toString().equals(childElement.tag().toString())) {
                continue;
            }


            Elements spans = childElement.getElementsByTag("span");
            if (spans.isEmpty()) {
                continue;
            }

            String id = childElement.attr("id").substring(9);

            Element span = spans.get(0);
            String tmpTime = span.text();

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            Date date = format.parse(tmpTime);


            Calendar calendar = Calendar.getInstance();
            if (time != null) {
                calendar.setTime(format.parse(time));
            } else {
                calendar.setTime(new Date());
            }

            calendar.add(Calendar.DATE, -7);
            Date current = calendar.getTime();

            if (current.after(date)) {
                break;
            }

            Element div = iterator.next();

            Elements aList = div.getElementsByAttributeValue("rel", "nofollow");
            for (Element a : aList) {
                List<String> versions = res.computeIfAbsent(a.text(), k -> new ArrayList<>());
                versions.add(id);
            }

        }
    }

    private static String getResponse(String url) throws IOException {

        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response = httpClient.execute(httpGet);
        HttpEntity entity = response.getEntity();
        return EntityUtils.toString(entity);

    }

}
